﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OOAD_Project_Engine.Foundation.Interfaces;
using OOAD_Project_Engine.Foundation;
using OOAD_Project_Engine.Foundation.MyEventArgs;

namespace OOAD_Project_Engine.Domain.Entities
{
    public class ComponentManager : EntityCollection, IComponentManager
    {
        List<IUpdateable> updateables = new List<IUpdateable>();
        List<IDrawable> drawables = new List<IDrawable>();
        List<IEntityComponent> componentsPendingRemoval = new List<IEntityComponent>();

        public void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            foreach (IEntityComponent iec in componentsPendingRemoval)
            {
                RemoveImmediate(iec);
            }
            componentsPendingRemoval.Clear();

            if (updateables.Count > 0)
            {
                foreach (IUpdateable updateable in updateables)
                {
                    if (updateable.Enabled)
                    {
                        updateable.Update(gameTime);
                    }
                }
            }
        }

        public void Draw(Microsoft.Xna.Framework.GameTime gameTime)
        {
            if (drawables.Count > 0)
            {
                foreach (IDrawable drawable in drawables)
                {
                    if (drawable.Visible)
                    {
                        drawable.Draw(gameTime);
                    }
                }
            }
        }

        protected override void OnEntityAdded(EntityEventArgs e)
        {
            base.OnEntityAdded(e);
            Entity entity = e.Entity as Entity;

            entity.ComponentAdded += new EventHandler<EntityComponentEventArgs>(entity_ComponentAdded);
            entity.ComponentRemoved += new EventHandler<EntityComponentEventArgs>(entity_ComponentRemoved);

            foreach (IEntityComponent component in entity)
                AddEntityComponent(component);
        }

        void entity_ComponentAdded(object sender, EntityComponentEventArgs e)
        {
            AddEntityComponent(e.Component);
        }

        void entity_ComponentRemoved(object sender, EntityComponentEventArgs e)
        {
        }

        private void AddEntityComponent(IEntityComponent component)
        {
            if (component is IDrawable)
            {
                IDrawable drawable = component as IDrawable;
                drawable.DrawOrderChanged += new EventHandler(drawable_DrawOrderChanged);

                drawables.Add(drawable);
                drawables.Sort(DrawOrderComparer.Default);
            }

            IUpdateable updateable = component as IUpdateable;
            component.UpdateOrderChanged += new EventHandler(component_UpdateOrderChanged);

            updateables.Add(updateable);
            updateables.Sort(UpdateOrderComparer.Default);
        }

        void component_UpdateOrderChanged(object sender, EventArgs e)
        {
            updateables.Sort(UpdateOrderComparer.Default);
        }

        void drawable_DrawOrderChanged(object sender, EventArgs e)
        {
            drawables.Sort(DrawOrderComparer.Default);
        }

        public bool Remove(IEntityComponent component)
        {
            if (!componentsPendingRemoval.Contains(component))
                componentsPendingRemoval.Add(component);
            return true;
        }

        protected override void OnEntityRemoved(EntityEventArgs e)
        {
            base.OnEntityRemoved(e);
            foreach (IEntityComponent c in e.Entity as IEntityComponentCollection)
            {
                Remove(c);
            }
        }

        public bool RemoveImmediate(IEntityComponent component)
        {
            //if (component.Owner.Contains(component))
            //{
            //    component.Owner.RemoveImmediate(component);
            //}

            if (component is IUpdateable)
            {
                IUpdateable updateable = component as IUpdateable;
                if (updateables.Contains(updateable))
                {
                    updateables.Remove(updateable);
                }
            }

            if (component is IDrawable)
            {
                IDrawable drawable = component as IDrawable;

                if (drawables.Contains(drawable))
                {
                    drawables.Remove(drawable);
                }
            }
            component.Dispose();
            return true;
        }

        public void LoadContent() {
            foreach (IDrawable drawable in drawables)
            {
                if (drawable is IDrawableContent)
                {
                    IDrawableContent drawableContent = drawable as IDrawableContent;
                    drawableContent.LoadContent();
                }
            }
        }

        public void UnloadContent() {
            foreach (IDrawable drawable in drawables)
            {
                if (drawable is IDrawableContent)
                {
                    IDrawableContent drawableContent = drawable as IDrawableContent;
                    drawableContent.UnLoadContent();
                }
            }
        }
    }
}
